#ifndef LOD_OBJ_LOADER_H
#define LOD_OBJ_LOADER_H

#include <map>
#include <vector>
#include "vertex.h"
#include "material.h"
#include "triangle.h"
#include "error.h"
#include "vect.h"
#include "object3d.h"


error load_gat(const char* path, std::vector<vertex>& verts, int& verts_count,
               std::vector<material>& materials, int& materials_count,
               std::vector<triangle>& triangles, int& trcount, std::pair<float,float>& xborders, 
               std::pair<float,float>& yborders, std::pair<float,float>& zborders);

int prepare_lod_base(std::vector<vertex>& verts, int verts_count,
               std::vector<material>& materials, int materials_count,
               std::vector<triangle>& triangles, int trcount,
               //std::vector<tvertex>& lverts, int& lverts_count,
               //std::vector<material>& lmaterials, int& lmaterials_count,
               //std::vector<triangle>& ltriangles, int& ltrcount);
               object3dv<tvertex>& lodbase, vect& mins, vect& maxs);


int clear_obj_data(object3dv<tvertex>& dirty, object3dv<vertex>& newlod,
               int vcount, int trcount,//materials are copied
               vect& min, vect& max);

inline float triangle_surface(std::vector<tvertex>& verts, int v1, int v2, int v3)
{
    // Surface of a triangle = 0.5 * dotproduct(vector1, vector2), 
    // when vector1 and vector2 makes the triangle.
    vect vec1(verts[v2].xyz[0] - verts[v1].xyz[0],
              verts[v2].xyz[1] - verts[v1].xyz[1],
              verts[v2].xyz[2] - verts[v1].xyz[2]);
    vect vec2(verts[v3].xyz[0] - verts[v1].xyz[0],
              verts[v3].xyz[1] - verts[v1].xyz[1],
              verts[v3].xyz[2] - verts[v1].xyz[2]);
    return 0.5f * vec1.dotproduct(vec2);
}

inline float triangle_surface(std::vector<tvertex>& verts, int v1, int v2, vertex& v3)
{
    // Surface of a triangle = 0.5 * dotproduct(vector1, vector2), when 
    // vector1 and vector2 makes the triangle.
    vect vec1(verts[v2].xyz[0] - verts[v1].xyz[0],
              verts[v2].xyz[1] - verts[v1].xyz[1],
              verts[v2].xyz[2] - verts[v1].xyz[2]);
    vect vec2(v3.xyz[0] - verts[v1].xyz[0],
              v3.xyz[1] - verts[v1].xyz[1],
              v3.xyz[2] - verts[v1].xyz[2]);
    return 0.5f * vec1.dotproduct(vec2);
}

inline void average_vertices(vertex& v1, vertex& v2, vertex& newv)
{
    // New vertex lies in the middle between the old ones.
    // It's normal vector is a sum of the old normal vectors.
    newv.xyz[0] = 0.5f * (v1.xyz[0] + v2.xyz[0]);
    newv.xyz[1] = 0.5f * (v1.xyz[1] + v2.xyz[1]);
    newv.xyz[2] = 0.5f * (v1.xyz[2] + v2.xyz[2]);
    newv.normal[0] = v1.normal[0] + v2.normal[0];
    newv.normal[1] = v1.normal[1] + v2.normal[1];
    newv.normal[2] = v1.normal[2] + v2.normal[2];
    newv.normalize_normalv();
}

float surface_factor(std::vector<tvertex>& verts, int vcount,
             std::vector<triangle>& triangles, int trcount,
             std::map<int,float>& trsurfaces, int v1, int v2);
             
std::pair<int,int> find_edge_to_collapse
        (std::vector<tvertex>& verts, int vcount,
         std::vector<triangle>& triangles, int trcount);

std::pair<int,int> random_edge(std::vector<triangle>& triangles, int trcount);

int full_edge_collapse
      (std::vector<tvertex>& verts, int& vcount, 
      std::vector<triangle>& triangles, int& trcount, int v1, int v2,
      int collapsion_type);

void clean_obj_data(std::vector<tvertex>& verts, int vcount, 
        std::vector<triangle>& triangles, int trcount);

int dispersed_cubes_lod(std::vector< object3dv<tvertex> >& lodbases, 
         const std::vector< std::pair<vect,vect> >& bases_ranges,
         int level, int tolevel, int vdelnum, int edgecolltype,
         int& newvcount, int& newtcount);



// Helping function for distant_edges()
void recursive_distant_edges(std::vector<tvertex>& verts, int vcount, 
        std::vector<int>& result, float& mindistance, int my_num, int istart, 
        std::vector<int>& chosenv);

/*vector<std::pair<int,int> >*/void distant_edges
      (std::vector<tvertex>& verts, int& vcount, 
       std::vector<triangle>& triangles, int& trcount, int n);

bool in_one_triangle(const std::vector<tvertex>& verts,
         const std::vector<triangle>& tris, int v1, int v2);

#endif
